/*
 * DxfGroups.java
 *
 * Created on 4 de Dezembro de 2007, 10:07
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package importadorDXF;

import java.io.*;
import java.util.Hashtable;

/**
 *
 * @author rafaelbuck
 */
public class DxfGroups
{
    private void init(DxfReaderReporter report, DxfFile file)
    {
        if(entityClassHead == null)
        {
            // recebe o nome do arquivo
            entityClassHead = getClass().getName();
            int dot = entityClassHead.lastIndexOf('.');
            if(dot == -1)
                entityClassHead = "Dxf";
            else
                entityClassHead = entityClassHead.substring(0, dot + 1) + "Dxf";
            try
            {
                dxfVertexClass = Class.forName(entityClassHead + "VERTEX");
            }
            catch(Exception _ex)
            {
                dxfVertexClass = null;
            }
        }
        
        //System.out.println("entityClassHead: " + entityClassHead);
        //System.out.println("dxfVertexClass: " + dxfVertexClass);
        
        this.file = file;
        reporter = report;
        if(report != null)
        {
            // retorna filetype
            int type = dxfStream.getType();
            //*****************************************************************
            // nao faz nada
            if((type & 0x30) != 0)
                report.showStatusRes("msgPacked");
            if(dxfStream.isBinary())
                report.showStatusRes("msgBinary");
            //******************************************************************
        }
    }

    /** Creates a new instance of DxfGroups */
    // Esse metodo eh utilizado pela classe DxfFile
    public DxfGroups(String fileName, DxfFile file, DxfReaderReporter report)
        throws DxfException
    {
        fileLength = -1L;
        reRead = false;
        dxfStream = new DedicatedDxfFileInputStream(fileName);
        fileLength = dxfStream.getFileLength();
        if(fileLength > 0L)
        {
            steps = fileLength / 200L / 10L;
            if(steps < 1L)
                steps = 1L;
            step = steps;
        } else
        //**********************************************************************
        // nao faz nada
        if(report != null)
            report.showProgress();
        //**********************************************************************
        init(report, file);
    }

    /** Creates a new instance of DxfGroups */
    public DxfGroups(InputStream is, DxfFile file, DxfReaderReporter report)
        throws DxfException
    {
        fileLength = -1L;
        reRead = false;
        dxfStream = new DedicatedDxfFileInputStream(is);
        init(report, file);
    }

    static byte type(short num)
    {
        if(num >= 0)
        {
            if(num < typeArr.length)
                return typeArr[num];
            if(num < 999)
                return typeArr[num % 100];
            if(num == 999)
                return -1;
            if(num < 1000 + eedTypeArr.length)
                return eedTypeArr[num - 1000];
        }
        return 0;
    }

    public byte type()
    {
        return type(number);
    }

    // Verifica se o aqruivo ja foi lido
    void unread()
    {
        reRead = true;
    }

    // Realiza a leitura do arquivo
    void read()
        throws DxfException
    {
        if(reRead)
        {
            reRead = false;
            return;
        }
        try
        {
            do
                number = dxfStream.read2Lines();
            while(type(number) <= 0);
            if(reporter != null && step-- <= 0L)
            {
                if(fileLength > 0L)
                    reporter.showProgress(dxfStream.getFilePointer(), fileLength);
                else
                    reporter.showProgress();
                step = steps;
            }
        }
        catch(IOException x)
        {
            throw new DxfException(x.getMessage() + " in line " + dxfStream.getLines());
        }
        catch(NumberFormatException _ex)
        {
            if(dxfStream.getLines() == 1)
                throw new DxfException("err!DxfFile");
            else
                throw new DxfException("err!Group", new String[] {
                    String.valueOf(dxfStream.getLines())
                });
        }
    }

    String valToString()
        throws DxfException
    {
        return dxfStream.getString();
    }

    float valToFloat()
        throws DxfException
    {
        return dxfStream.getFloat();
    }

    int valToInt()
        throws DxfException
    {
        return dxfStream.getInt();
    }

    short valToColor()
        throws DxfException
    {
        return dxfStream.getColor();
    }

    DxfEntity entityByName(String name)
    {
        if(dxfClassTable == null)
            dxfClassTable = new Hashtable(64);
        
        Class c = (Class)dxfClassTable.get(name);
        
        if(c == null)
            try
            {
                try
                {
                    c = Class.forName(entityClassHead + name);
                }
                catch(Exception _ex)
                {
                    if(reporter != null)
                        reporter.warnUnknownEntity(name);
                    
                    c = Class.forName(entityClassHead + "Entity");
                }
                
                dxfClassTable.put(name, c);
            }
            catch(Exception _ex)
            {
                return new DxfEntity();
            }
        
        try
        {
            return (DxfEntity)c.newInstance();
        }
        catch(Exception _ex)
        {
            return new DxfEntity();
        }
    }

    DxfTable tableByName(String name)
    {
        if(dxfClassTable == null)
            dxfClassTable = new Hashtable(64);
        Class c = (Class)dxfClassTable.get(name);
        if(c == null)
            try
            {
                try
                {
                    c = Class.forName(entityClassHead + name);
                }
                catch(Exception _ex)
                {
                    c = Class.forName(entityClassHead + "Table");
                }
                dxfClassTable.put(name, c);
            }
            catch(Exception _ex)
            {
                return new DxfTable();
            }
        try
        {
            return (DxfTable)c.newInstance();
        }
        catch(Exception _ex)
        {
            return new DxfTable();
        }
    }

    public void readEntities(DxfEntityCollector cool)
        throws DxfException
    {
        readEntitiesInternally(cool);
        unread();
    }

    private void readEntitiesInternally(DxfEntityCollector cool)
        throws DxfException
    {
        DxfEntity e = null;
        do
        {
            try
            {
                read();
            }
            catch(Exception x)
            {
                String msg = x.getMessage();
                throw new DxfException("err!Read", new String[] {
                    msg != null ? msg : x.toString(), String.valueOf(dxfStream.getLines())
                });
            }
            if(number == 0)
            {
                if(e != null)
                {
                    DxfEntityCollector collector = e.getEntityCollector();
                    if(collector != null)
                    {
                        unread();
                        readEntitiesInternally(collector);
                    }
                    
                    e.finishRead(file);
                    
                    try
                    {
                        if(!cool.addEntity(e))
                            return;
                    }
                    catch(DxfUnsupportedException x)
                    {
                        String msg = x.getMessage();
                        throw new DxfException("err!Read", new String[] {
                            msg != null ? msg : x.toString(), String.valueOf(dxfStream.getLines())
                        });
                    }
                }
                
                e = entityByName(dxfStream.getString());
            } else
            {
                set(e);
            }
        } while(true);
    }

    private void set(DxfInterface inter) throws DxfException
    {
        if(inter != null && number > 0)
            switch(type(number))
            {
            case 1: // '\001'
                inter.setGroup(number, valToString());
                break;

            case 2: // '\002'
                inter.setGroup(number, valToInt());
                break;

            case 3: // '\003'
                inter.setGroup(number, valToFloat());
                break;

            case 4: // '\004'
                inter.setGroup(number, valToColor());
                break;
            }
    }

    void readTables(DxfTableCollector cool)
        throws DxfException
    {
        readTables(cool, false);
    }

    void readTables(DxfTableCollector cool, boolean reuseFirst)
        throws DxfException
    {
        DxfTable t = null;
        do
        {
            if(reuseFirst)
                reuseFirst = false;
            else
                read();
            if(number == 0)
            {
                if(t != null)
                {
                    t.finishRead(file);
                    try
                    {
                        cool.addTable(t);
                    }
                    catch(Exception _ex) { }
                    t = null;
                }
                t = tableByName(dxfStream.getString());
                if(t.isTerm())
                    return;
            } else
            {
                set(t);
            }
        } while(true);
    }

    public String toString()
    {
        try
        {
            return "#" + number + ":\t'" + dxfStream.getString() + "'";
        }
        catch(DxfException _ex)
        {
            return "#" + number + ":\t???";
        }
    }

    public int getLineNr()
    {
        return dxfStream.getLines();
    }

    static final byte COMMENT = -1;
    static final byte NOTHING = 0;
    static final byte STRING = 1;
    static final byte VARNAME = 1;
    static final byte LAYER = 1;
    static final byte LTYPE = 1;
    static final byte ENTITY = 1;
    static final byte CLASS = 1;
    static final byte INT = 2;
    static final byte COUNTER = 2;
    static final byte FLOAT = 3;
    static final byte XVAL = 3;
    static final byte YVAL = 3;
    static final byte ZVAL = 3;
    static final byte COLOR = 4;
    static final byte BYTEARR = 5;
    static final byte LONGINT = 6;
    static final int COMMENT_NUM = 999;
    static final int EED_START = 1000;
    private static final byte typeArr[] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 
        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 
        2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        1, 0, 0, 0, 0, 0, 0, 0, 0, 0
    };
    private static final byte eedTypeArr[] = {
        1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
        2, 6, 2, 2, 2, 2, 2, 2, 2, 2
    };
    private Hashtable dxfClassTable;
    private static String entityClassHead = null;
    private static Class dxfVertexClass;
    private DedicatedDxfFileInputStream dxfStream;  // Stream do arquivo DXF
    protected short number;
    protected DxfFile file;
    protected DxfReaderReporter reporter;           // vem da classe principal
    private long steps;                             // usado na instanciacao >=1
    private long step;                              // usado na instanciacao >=1
    protected long fileLength;
    private boolean reRead;                         // lido(true)-nao lido(false)

}